package zack.project.domain.strategy.service.rule.tree.factory.engine.impl;

import lombok.extern.slf4j.Slf4j;
import zack.project.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import zack.project.domain.strategy.model.valobj.RuleTreeNodeLineVO;
import zack.project.domain.strategy.model.valobj.RuleTreeNodeVO;
import zack.project.domain.strategy.model.valobj.RuleTreeVO;
import zack.project.domain.strategy.service.rule.tree.ILogicTreeNode;
import zack.project.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import zack.project.domain.strategy.service.rule.tree.factory.engine.IDecisionTreeEngine;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**决策树引擎
 * @author A1793
 */
@Slf4j
public class DecisionTreeEngine implements IDecisionTreeEngine {
    //决策树节点
    private final Map<String, ILogicTreeNode> logicTreeNodeMap;
    //数据库配置的规则树
    private final RuleTreeVO ruleTreeVO;

    public DecisionTreeEngine(Map<String, ILogicTreeNode> logicTreeNodeMap, RuleTreeVO ruleTreeVO) {
        this.logicTreeNodeMap = logicTreeNodeMap;
        this.ruleTreeVO = ruleTreeVO;
    }

    /**
     * 执行规则树
     * @param userId
     * @param strategyId
     * @param awardId
     * @param endDateTime
     * @return
     */
    @Override
    public DefaultTreeFactory.StrategyAwardVO process(String userId,
                                                      Long strategyId,
                                                      Integer awardId,
                                                      Date endDateTime) {
        //获取规则节点表
        Map<String, RuleTreeNodeVO> ruleTreeNodeVOMap = ruleTreeVO.getTreeNodeMap();
        //获取规则树的根节点名
        String nextNode = ruleTreeVO.getTreeRootRuleNode();
        //在规则表中获取对应的规则树节点
        RuleTreeNodeVO treeNodeVO = ruleTreeNodeVOMap.get(nextNode);
        DefaultTreeFactory.StrategyAwardVO strategyAwardVO = null;
        //这里为空的时候会退出循环
        //比如:
        //lockCount节点放行到stockCount节点，库存节点库存抢占成功会返回TAKE_OVER,
        // 这个TakeOver在数据库没有配置stockCount节点关于takeover会路由到哪个节点，所以获取stock节点的nodeLine，
        // 在循环判断（nextNode方法）的时候，只能返回空(没有nodeLineVO的ruleLimitValue是TAKEOVER)，返回空之后再从nodeMap获取只能是null，
        // 退出决策树节点过滤
        while (treeNodeVO != null) {
            //策略模式,根据节点名来来获取对应的决策树节点
            ILogicTreeNode iLogicTreeNode = logicTreeNodeMap.get(treeNodeVO.getRuleKey());
            //该规则节点的规则值
            String ruleValue = treeNodeVO.getRuleValue();
            DefaultTreeFactory.TreeActionEntity treeActionEntity =
                    iLogicTreeNode.logic(userId, strategyId, awardId,ruleValue,endDateTime);

            RuleLogicCheckTypeVO ruleLogicCheckType = treeActionEntity.getRuleLogicCheckType();
            strategyAwardVO = treeActionEntity.getStrategyAwardVO();
            log.info("决策树引擎【{}】treeId:{} node:{} code:{}", ruleTreeVO.getTreeName(), ruleTreeVO.getTreeId(), nextNode, ruleLogicCheckType.getCode());
            //根据上一个决策节点的执行结果(ruleLogicCheckType),在规则节点的TreeNodeLineVOList获得下一个决策节点
             nextNode = nextNode(ruleLogicCheckType.getCode(), treeNodeVO.getTreeNodeLineVOList());
             treeNodeVO = ruleTreeNodeVOMap.get(nextNode);
        }

        return strategyAwardVO;

    }

    /**
     * 路由到下一个决策节点
     * @param matterValue
     * @param ruleTreeNodeLineVOList
     * @return
     */
    private String nextNode(String matterValue, List<RuleTreeNodeLineVO> ruleTreeNodeLineVOList) {
        if(ruleTreeNodeLineVOList == null || ruleTreeNodeLineVOList.isEmpty()) {
            return null;
        }
        for(RuleTreeNodeLineVO ruleTreeNodeLineVO : ruleTreeNodeLineVOList) {
            if(decisionLogic(matterValue, ruleTreeNodeLineVO)) {
                return ruleTreeNodeLineVO.getRuleNodeTo();
            }
        }
       return null;
    }

    /**
     * 1	tree_lock_1	rule_lock	rule_stock	EQUAL	ALLOW	0000-00-00 00:00:00	2024-02-15 07:55:08
     * 2	tree_lock_1	rule_lock	rule_luck_award	EQUAL	TAKE_OVER	0000-00-00 00:00:00	2024-02-15 07:55:11
     * 3	tree_lock_1	rule_stock	rule_luck_award	EQUAL	ALLOW	0000-00-00 00:00:00	2024-02-15 07:55:13
     * 举例说明: 当根节点是rule_lock时且执行结果是ALLOW,此时遍历其对应的ruleTreeNodeLineVOList的ruleTreeNodeLineVO，
     * 如果也匹配到了ALLOW,则返回true,走rule_stock决策节点;当执行结果是TAKE_OVER(已抽奖次数小于规则值),此时走rule_luck_award决策节点
     * @param matterValue
     * @param ruleTreeNodeLineVO
     * @return
     */
    private boolean decisionLogic(String matterValue, RuleTreeNodeLineVO ruleTreeNodeLineVO) {
        switch(ruleTreeNodeLineVO.getRuleLimitType()){
            //在node_line列表找rule_limit_value和传入的checkType相等的nodeLine
            case  EQUAL:return matterValue.equals(ruleTreeNodeLineVO.getRuleLimitValue().getCode());
            case GT:
            case LT:
            case GE:
            case LE:
            case ENUM:
            default:
                return false;

        }
    }
}
